﻿#ifndef QBLOCK_H
#define QBLOCK_H

#include <QtCore>
#include <QtGui>
#include <QWidget>
#include <QGraphicsPixmapItem>
#include <QDomDocument>
#include <QMenu>

#include "QFlowEnum.h"
#include "FlowChart_Global.h"
#include "FlowCellParam.h"


#define CVV_VERSION "1.2"

namespace CVV
{

namespace FlowChart
{

class QFlowChart;

class CVV_FLOWCHART_EXPORT QBlock : public QWidget
{
    Q_OBJECT

public:
    explicit QBlock(QWidget *parent = nullptr);
    explicit QBlock(QMenu *blockMenu, const QString & aType = QString(), QWidget *parent = nullptr);
    ~QBlock()override;

    /**
     * @brief root 根节点
     * @return
     */
    QBlock *root();

    /**
     * @brief 设置为子流程节点
     */
    void setIsSubProcess();

    /**
     * @brief isBockType 是否是节点类型
     * @param blocktype
     * @return
     */
    bool isBockType (QFlowEnum::BlockType blocktype) const;

    QString type(int flag = 0 ) const;
    void setType(const QString & newType);

    /**
     * @brief index
     * @return
     */
    int index();

    /**
     * @brief insert
     * @param newIndex
     * @param aBlock
     */
    void insert(int newIndex, QBlock *aBlock);

    /**
     * @brief remove
     * @param aBlock
     */
    void remove(QBlock *aBlock);

    /**
     * @brief append
     * @param aBlock
     */
    void append(QBlock *aBlock);

    /**
     * @brief deleteObject
     * @param aIndex
     */
    void deleteObject(int aIndex);

    /**
     * @brief item
     * @param aIndex
     * @return
     */
    QBlock* item(int aIndex) const;

    /**
     * @brief setItem
     * @param aIndex
     * @param aBlock
     */
    void setItem(int aIndex, QBlock *aBlock);

    /**
     * @brief flowChart
     * @return
     */
    QFlowChart * flowChart() const;

    /**
     * @brief setFlowChart
     * @param aFlowChart
     */
    void setFlowChart(QFlowChart * aFlowChart);

    /**
     * @brief clear
     */
    void clear();

    /**
       * @brief adjustSize 调整block 大小
       * @param aZoom
       */
    void adjustSize(const double aZoom);

    /**
       * @brief adjustPosition 调整block位置
       * @param ox block x
       * @param oy block y
       */
    void adjustPosition(const double ox, const double oy);

    /**
       * @brief paint  在流程图画板上绘制区域
       * @param canvas  流程图画板
       * @param fontSizeInPoints
       */
    void paint(QPainter *canvas, bool fontSizeInPoints = false);

    /**
      * @brief 绘制block，选择虚线外边框
      * @param
      * @return
      */
    void paintBlockMargin(QPainter *canvas, QColor col = QColor(0x12,0x96,0xdb), bool isSelected = false);

    /**
     * @brief zoom
     * @return
     */
    double zoom() const;

    /**
     * @brief blockAt
     * @param px
     * @param py
     * @return
     */
    QBlock * blockAt(int px, int py);

    /**
     * @brief xmlNode
     * @param doc
     * @return
     */
    QDomElement xmlNode(QDomDocument & doc) const;
    void setXmlNode(const QDomElement & node);
    QBlock* insertXmlTree(int aIndex, const QDomElement & algorithm);

    /**
     * @brief isActive
     * @return
     */
    bool isActive() const;

    /**
     * @brief drawCaption
     * @param canvas
     * @param rect
     * @param zoomFactor
     * @param text
     */
    static void drawCaption(QPainter *canvas, const QRectF & rect, const double zoomFactor, const QString & text);

    /**
     * @brief modify
     * @param num
     * @param bAdd
     */
    void modify(int num, bool bAdd = true, const QList<int>& lstDeleteIndex = QList<int>());

    /**
     * @brief updateParallelBranchStatus 更新平行分支的启用状态
     * @param lstEnableIndex
     */
    void updateParallelBranchStatus(const QList<int> &lstEnableIndex);

    /**
     * @brief setPluginInfo
     * @param param
     */
    void setPluginInfo(const QList<CVV::Interface::FlowCellParam> &param);
    QList<CVV::Interface::FlowCellParam> getPluginInfo() const;

    /**
     * @brief makeBackwardCompatibility
     */
    void makeBackwardCompatibility();

    /**
     * @brief setAlgorithmParams 设置算法参数
     * @param lstAlgParam
     */
    void setAlgorithmParams(const QList<CVV::Interface::FlowCellParam> &lstAlgParam);
    QList<CVV::Interface::FlowCellParam> getAlgorithmParams() const;

    /**
     * @brief setId 当前节点ID
     * @param id
     */
    void setId(const QString &id);
    QString id() const;

    /**
     * @brief setPreId 前节点ID
     * @param id
     */
    void setPreId(const QString &id);
    QString preId() const;

    /**
     * @brief updateAllNodePreId 更新主分支的前节点id
     */
    void updateAllNodePreId();

    /**
     * @brief setBranchEnable 分支是否启用
     * @param bEnable
     */
    void setBranchEnable(bool bEnable);
    bool branchEnable() const;

    /**
      * @brief getKeywordMatchedResult 判断搜索关键字是否匹配
      * @param keyWord
      * @return bool
      */
     bool getKeywordMatchedResult(const QString &keyWord, int seachType = 0);

     /**
       * @brief setBlockExpandState 设置节点展开与否
       * @param expandState
       * @return bool
       */
     void setBlockExpandState(bool expandState);
     bool getBlockExpandState();

     /**
       * @brief setBlockVisible 设置节点是否可见
       * @param visible
       * @return bool
       */
     void setBlockVisible(bool visible);
     bool getBlockVisible();

     /**
       * @brief setDescibe 设置节点的描述
       * @param desStr
       */
     void setDescibe(const QString & desStr);
     QString getDescibe() const;

     /**
       * @brief setSceneStr 设置获取场景设置
       */
     void setSceneStr(const QString & scene);
     QString getSceneStr() const;

private:
    /**
     * @brief createCellParamNode cell参数节点
     * @param doc
     * @param cellElement
     */
    void createCellParamNode(QDomDocument &doc, QDomElement &cellElement) const;

    /**
     * @brief createAlgorithmParamNode 创建算法参数节点
     * @param algEle
     */
    void createAlgorithmParamNode(QDomDocument &doc, QDomElement &algEle) const;

    /**
     * @brief createUserTypeValueNode 自定义数据类型节点定义
     * @param doc
     * @param ele
     * @param userTypeValue
     * @param userTypeCode
     */
    void createUserTypeValueNode(QDomDocument &doc,
                                 QDomElement &ele,
                                 const QVariant &userTypeValue,
                                 const QString &userTypeCode) const;

    /**
     * @brief updateAfterInsertNodePreId
     * @param preId
     * @param index
     */
    void updateAfterInsertNodePreId(const QString &preId, int index);

    /**
     * @brief parserParamString
     * @param type 格式为xxx<xxx>
     * @return 尖括号内的字符串
     */
    QString parserParamString(const QString &type) const;

    /**
     * @brief findPreId 查找前节点ID
     * @param aBlock
     * @return
     */
    QString findPreId(QBlock *aBlock);
    void findChildId(QBlock *aBlock, QStringList &lstPreId);

    /**
     * @brief updateAllNodePreId
     * @param aBlock
     */
    void updateAllNodePreId(QBlock *aBlock);

    /**
      * @brief 参数匹配
      * @param
      * @return bool
      */
    bool checkParamByKeyWord(CVV::Interface::FlowCellParam &param, const QString &keyWord, int serchType);

    /**
     * @brief 普通模式匹配/区分大小写
     */
    bool commonMatch(CVV::Interface::FlowCellParam &param, const QString &keyWord, bool bFlag);

    /**
     * @brief 全词匹配/区分大小写
     */
    bool wholdWordMatch(CVV::Interface::FlowCellParam &param, const QString &keyWord, bool bFlag);

    /**
     * @brief 正则匹配校验
     */
    bool RegExpMatch(CVV::Interface::FlowCellParam &param, const QString &keyWord);

    bool VariantMatch(int matchId, bool bFlag, QString &srcStr, QVariant &var);

public:
    double m_dX;
    double m_dY;
    double m_dWidth;                                        // 绘制宽度
    double m_dHeight;                                       // 绘制高度
    double m_dExpandW;                                      // 展开宽度
    double m_dExpandH;                                      // 展开高度
    double m_dTopMargin;
    double m_dBottomMargin;
    double m_dLeftMargin;
    double m_dRightMargin;
    QString m_descibe{""};                                  // root 节点描述
    QString m_scene{""};                                    // root 场景数据
    QString m_strId;                                        // 当前节点Id
    QString m_strPreId;                                     // 当前节点前一个Id

    QBlock *m_pParentBlock{nullptr};                        // 父节点
    QMenu* m_pBlockMenu{nullptr};                           // 右键菜单

    bool m_bSelectAll{false};                               // 是否全选
    bool m_bIsBranch{false};                                // 是否分支
    bool m_bFindActive{false};                              // Blockd为目标查找对象
    bool m_bCurFindActive{false};                           // 当前查找到Block，激活的标志
    bool m_bBranchEnable{true};                             // 分支是否启用 默认启用
    bool m_bIsExpand{true};                                 // 默认节点是展开显示的
    bool m_bVisible{true};                                  // 默认可见的
    bool m_bSubProcess{false};                              // 是否为子方案节点(默认为false)
    QList<QBlock*> m_lstChildItems;                         // 存储当前节点的子节点 Branch item
    QHash<QString, QString> m_hashAttributes;               // 当前节点的属性列表
    QList<CVV::Interface::FlowCellParam> m_pluginInfoList;  // 插件参数列表
    QList<CVV::Interface::FlowCellParam> m_lstAlgParam;     // 算法插件参数列表
    QDomElement m_child;                                    // 保存parallel最后的baranch分支节点

private:
    QFlowChart *m_pFlowChart{nullptr};                      // 流程图
};

}

}
#endif // QBLOCK_H
